package com.mxpio.erp.equipment.service.impl;

import com.mxpio.erp.common.equipment.entity.EquipmentArea;
import com.mxpioframework.common.exception.MBootException;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.mxpio.erp.common.equipment.service.EquipmentAreaService;
import com.mxpioframework.system.service.impl.BaseServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 区域结构设置Service业务层处理
 *
 * @author Cheng
 * @date 2023-06-24
 */
@Service
public class EquipmentAreaServiceImpl extends BaseServiceImpl<EquipmentArea> implements EquipmentAreaService {
    /**
     * 根节点父ID的值
     */
    public static final String ROOT_PID_VALUE = "0";

    @Override
    @Transactional(readOnly = false)
    public void addArea(EquipmentArea equipmentArea) {
        equipmentArea.setHasChild(false);
        if (StringUtils.isBlank(equipmentArea.getPid())
                || ROOT_PID_VALUE.equals(equipmentArea.getPid())) {
            equipmentArea.setPid(ROOT_PID_VALUE);
        } else {
            //如果当前节点父ID不为空 则设置父节点的hasChildren 为1
            EquipmentArea parent = getById(EquipmentArea.class, equipmentArea.getPid());
            if (parent != null) {
                //校验层级
                int areaLevel = findAreaLevel(equipmentArea.getPid());
                if (areaLevel > 3) {
                    throw new MBootException("超过最大4层级");
                }

                //设置厂区
                equipmentArea.setFactory(parent.getFactory());
                //若上级节点为禁用状态该节点也为禁用状态
                equipmentArea.setIsEnable(parent.getIsEnable());
                if (!parent.getHasChild()) {
                    this.updateTreeNodeStatus(parent.getId(), true);
                }
            }

        }
        this.save(equipmentArea);
    }

    /**
     * 获取当前节点层级
    * @param targetId
     * @return
     */
    private int findAreaLevel(String targetId){
        List<EquipmentArea> list = this.list(EquipmentArea.class, Criteria.create());
        Map<String, EquipmentArea> areaMap = list.stream()
                .collect(Collectors.toMap(area -> area.getId(), area -> area));

        if (!areaMap.containsKey(targetId)) {
            return -1; // 如果目标id不存在于列表中，返回-1表示未找到
        }

        int currentLevel = 0;
        String currentId = targetId;

        while (!ROOT_PID_VALUE.equals(currentId)) {
            currentId = areaMap.get(currentId).getPid();
            currentLevel++;
        }

        return currentLevel;

    }

    /**
     * 获取当前节点子节点层级数
     * @param targetId
     * @return
     */
    public int findChildDepth(String targetId) {
        List<EquipmentArea> list = this.list(EquipmentArea.class, Criteria.create());
        Map<String, List<String>> tree = new HashMap<>();
        for (EquipmentArea area : list) {
            String parentId = area.getPid();
            tree.computeIfAbsent(parentId, k -> new ArrayList<>()).add(area.getId());
        }
        return dfs(tree, targetId);
    }

    private int dfs(Map<String, List<String>> tree, String nodeId) {
        if (!tree.containsKey(nodeId)) {
            return 0;
        }
        List<String> children = tree.get(nodeId);
        int maxDepth = 0;
        for (String child : children) {
            maxDepth = Math.max(maxDepth, dfs(tree, child));
        }
        return maxDepth + 1;
    }


    @Override
    @Transactional(readOnly = false)
    public void deleteArea(String id) {
        //查询选中节点下所有子节点一并删除
        id = this.queryTreeChildIds(id);
        if (id.indexOf(",") > 0) {
            StringBuffer sb = new StringBuffer();
            String[] idArr = id.split(",");
            for (String idVal : idArr) {
                if (StringUtils.isNotBlank(idVal)) {
                    EquipmentArea equipmentArea = this.getById(EquipmentArea.class, idVal);
                    if (equipmentArea != null) {
                        String pidVal = equipmentArea.getPid();
                        //查询此节点上一级是否还有其他子节点
                        Long count = JpaUtil.linq(EquipmentArea.class).equal("pid", pidVal).notIn("id", Arrays.asList(idArr)).count();
                        if ((count == null || count == 0) && !Arrays.asList(idArr).contains(pidVal)
                                && !sb.toString().contains(pidVal)) {
                            //如果当前节点原本有子节点 现在木有了，更新状态
                            sb.append(pidVal).append(",");
                        }
                    }
                }
            }
            //批量删除节点
            Criteria c = Criteria.create().addCriterion("id", Operator.IN, Arrays.asList(idArr));
            this.deleteBatch(EquipmentArea.class, c);
            //修改已无子节点的标识
            String[] pidArr = sb.toString().split(",");
            for (String pid : pidArr) {
                this.updateOldParentNode(pid);
            }
        } else {
            EquipmentArea equipmentArea = getById(EquipmentArea.class, id);
            if (equipmentArea != null) {
                this.delete(EquipmentArea.class, id);
                this.updateOldParentNode(equipmentArea.getPid());
            }
        }
    }

    @Override
    @Transactional(readOnly = false)
    public void updateArea(EquipmentArea equipmentArea) {
        EquipmentArea entity = this.getById(EquipmentArea.class, equipmentArea.getId());
        if (entity == null) {
            throw new MBootException("未找到对应记录！");
        }
        String old_pid = entity.getPid();
        String new_pid = equipmentArea.getPid();
        if (!old_pid.equals(new_pid)) {
            //校验层级
            int areaLevel = findAreaLevel(equipmentArea.getPid());
            int childDepth = findChildDepth(equipmentArea.getId());
            if (areaLevel+childDepth > 4) {
                throw new MBootException("超过最大4层级");
            }

            this.updateOldParentNode(old_pid);
            if (StringUtils.isBlank(new_pid)) {
                equipmentArea.setPid(ROOT_PID_VALUE);
            }
            if (!ROOT_PID_VALUE.equals(equipmentArea.getPid())) {
                this.updateTreeNodeStatus(equipmentArea.getPid(), true);
            }
        }
        //判断禁用状态或者厂区是否改变
        if (entity.getIsEnable() != equipmentArea.getIsEnable() ||
                (entity.getFactory()!=null && !entity.getFactory().equals(equipmentArea.getFactory())) ||
                (equipmentArea.getFactory()!=null && !equipmentArea.getFactory().equals(entity.getFactory()))) {
            //修改所有下级为上级状态
            String ids = queryTreeChildIds(equipmentArea.getId());
            JpaUtil.linu(EquipmentArea.class)
                    .set("isEnable", equipmentArea.getIsEnable())
                    .set("factory", equipmentArea.getFactory())
                    .in("id", Arrays.asList(ids.split(",")))
                    .update();
        }
        this.update(equipmentArea);

    }

    /**
     * 根据id查询所有子节点id
     *
     * @param ids
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public String queryTreeChildIds(String ids) {
        //获取id数组
        String[] idArr = ids.split(",");
        StringBuffer sb = new StringBuffer();
        for (String pidVal : idArr) {
            if (pidVal != null) {
                if (!sb.toString().contains(pidVal)) {
                    if (sb.toString().length() > 0) {
                        sb.append(",");
                    }
                    sb.append(pidVal);
                    this.getTreeChildIds(pidVal, sb);
                }
            }
        }
        return sb.toString();
    }

    /**
     * 递归查询所有子节点
     *
     * @param pidVal
     * @param sb
     * @return
     */
    private StringBuffer getTreeChildIds(String pidVal, StringBuffer sb) {
        List<EquipmentArea> dataList = JpaUtil.linq(EquipmentArea.class).equal("pid", pidVal).list();
        if (dataList != null && dataList.size() > 0) {
            for (EquipmentArea tree : dataList) {
                if (!sb.toString().contains(tree.getId())) {
                    sb.append(",").append(tree.getId());
                }
                this.getTreeChildIds(tree.getId(), sb);
            }
        }
        return sb;
    }

    /**
     * 根据所传pid查询旧的父级节点的子节点并修改相应状态值
     *
     * @param pid
     */
    public void updateOldParentNode(String pid) {
        if (!ROOT_PID_VALUE.equals(pid)) {
            Long count = JpaUtil.linq(EquipmentArea.class).equal("pid", pid).count();
            if (count == null || count <= 1) {
                updateTreeNodeStatus(pid, false);
            }
        }
    }

    public void updateTreeNodeStatus(String id, Boolean hasChild) {
        JpaUtil.linu(EquipmentArea.class).set("hasChild", hasChild).equal("id", id).update();
    }

    @Override
    public String getParentAllNameByPid(String pid) {
        String name = "";
        if (StringUtils.isBlank(pid)) {
            return name;
        }
        if (!"0".equals(pid)) {
            return this.getParentAllNameByPid(pid, name);
        } else {
            return name;
        }
    }

    @Override
    public List<EquipmentArea> getFatherList(List<EquipmentArea> list, String idVal) {
        EquipmentArea data = this.getById(EquipmentArea.class, idVal);
        list.add(data);
        if (data != null && !"0".equals(data.getPid())) {
            return this.getFatherList(list, data.getPid());
        } else {
            return list;
        }
    }

    private String getParentAllNameByPid(String pid, String name) {
        EquipmentArea data = this.getById(EquipmentArea.class, pid);
        if (data != null && !"0".equals(data.getPid())) {
            name = data.getAreaName() + "/" + name;
            return this.getParentAllNameByPid(data.getPid(), name);
        } else {
            name = data.getAreaName() + "/" + name;
            return name;
        }
    }
}
